using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using COLLADA;
using GingerBeard.Utilities;
using System.Diagnostics;

namespace ColladaToData
{
	internal class ColladaToData
	{
		public static void Convert(Document inDoc, Stream outStream, String inPlatform)
		{
			new ColladaToData(inDoc, outStream, inPlatform);
		}

		private Document doc;
		private String platform;
		private Data.RenderData renderData;
		private Dictionary<UInt32, Int32> gpuProgramCache = new Dictionary<UInt32, Int32>();
		private Dictionary<UInt32, Int32> textureCache = new Dictionary<UInt32, Int32>();
		private Dictionary<Document.Geometry, Data.Model> modelLookup = new Dictionary<Document.Geometry, Data.Model>();

		private class MaterialBinding
		{
			public String bindingTarget;
			public Data.Material boundMaterial;
		}

		private Dictionary<String, MaterialBinding> materialBindings = new Dictionary<String, MaterialBinding>();

		private ColladaToData(Document inDoc, Stream outStream, String inPlatform)
		{
			doc = inDoc;
			renderData = new Data.RenderData();
			platform = inPlatform;

			Conditioner.AxisConversionToYAxis(doc);
			Conditioner.ConvexTriangulator(doc);
			Conditioner.Reindexor(doc);

			Document.VisualScene scene = doc.dic[doc.instanceVisualScene.url.Fragment] as Document.VisualScene;
			if (scene == null) throw new Exception("Document doesn't contain a visual scene");

			foreach (Document.Material material in doc.materials)
				ProcessMaterial(material);

			foreach (Document.Node node in scene.nodes)
				GetMaterialBindings(node);

			foreach (Document.Geometry geo in doc.geometries)
				ProcessGeometry(geo);

			foreach (Document.Node node in scene.nodes)
				ProcessNode(node);
			
			// Now save out the renderdata block
			MemoryStream memStream = null;
			UInt32 renderDataLength = 0;
			using (memStream = new MemoryStream())
			{
				using (BinaryWriter writer = new BinaryWriter(memStream))
				{
					renderData.Write(writer);
					renderDataLength = (UInt32)memStream.Length;
				}

				using (BinaryWriter writer = new BinaryWriter(outStream))
				{
					Data.DataBlockHeader mainHeader = new Data.DataBlockHeader();
					mainHeader.Id = GingerBeard.Utilities.Crc.GetInstance().GenerateCrc("DATA");
					mainHeader.SizeInBytes = 0;
					mainHeader.Write(writer);

					Data.DataBlockHeader renderDataHeader = new Data.DataBlockHeader();
					renderDataHeader.Id = GingerBeard.Utilities.Crc.GetInstance().GenerateCrc("RDAT");
					renderDataHeader.SizeInBytes = renderDataLength;
					renderDataHeader.Write(writer);

					writer.Write(memStream.GetBuffer());
				}
			}
		}

		private void GetMaterialBindings(Document.Node node)
		{
			if (node.instances != null)
			{
				foreach (Document.Instance instance in node.instances)
				{
					if (instance is Document.InstanceGeometry)
					{
						Document.InstanceWithMaterialBind bind = (Document.InstanceWithMaterialBind)instance;

						foreach (String instanceMatName in bind.bindMaterial.instanceMaterials.Keys)
						{
							Document.InstanceMaterial matInstance = bind.bindMaterial.instanceMaterials[instanceMatName];
							MaterialBinding newBinding = new MaterialBinding();
							newBinding.bindingTarget = instanceMatName;

							List<Object> materialObjects = renderData.GetObjects<Data.Material>();
							foreach (Object o in materialObjects)
							{
								Data.Material m = o as Data.Material;
								if (m.name == Crc.GetInstance().GenerateCrc(instanceMatName))
								{
									newBinding.boundMaterial = m;
									break;
								}
							}
							materialBindings[matInstance.symbol] = newBinding;
						}
					}
				}
			}

			if (node.children != null)
			{
				foreach (Document.Node child in node.children)
				{
					ProcessNode(child);
				}
			}
		}

		private void ProcessGeometry(Document.Geometry geo)
		{
			Data.Model model = new Data.Model();
			renderData.AddObject(model);
			modelLookup[geo] = model;
			
			Data.ModelLod lod = new Data.ModelLod();
			model.idxFirstLod = renderData.AddObject(lod);
			model.numLods = 1;

			List<Data.Submodel> submodels = new List<Data.Submodel>();

			Int32 idxVertexBuffer = -1;

			foreach (Document.Primitive primitive in geo.mesh.primitives)
			{
				// Test to make sure the 'vertexBuffer' conditioner worked
				if (idxVertexBuffer == -1)
				{
					Dictionary<String, Document.Input> inputs = new Dictionary<string, Document.Input>();
					foreach (Document.Input input in Util.getAllInputs(doc, primitive))
						if (inputs.ContainsKey(input.semantic))
							throw new Exception("Cannot handle multiple " + input.semantic + " case in COLLADAModel");
						else
						{
							inputs[input.semantic] = input;
							if (input.semantic == "POSITION")
							{
								Data.Buffer vertexBuffer = new Data.Buffer();
								idxVertexBuffer = renderData.AddObject(vertexBuffer);
								float[] data = (((Document.Source)input.source).array as Document.Array<float>).arr;
								Byte[] initData = ByteConversion.ToByteArray(data);
								vertexBuffer.idxInitData = renderData.AddBoxedObjects(initData);
								vertexBuffer.numInitDataBytes = (UInt32)initData.Length;
								vertexBuffer.numElements = (UInt32)((Document.Source)input.source).accessor.count;
								vertexBuffer.format = Data.BufferFormat.VertexStream;

								UInt32 curOffset = 0;
								Data.BufferDeclaration decl = new Data.BufferDeclaration();
								vertexBuffer.idxDeclaration = renderData.AddObject(decl);

								UInt32[] floatTypes = {
									Crc.GetInstance().GenerateCrc("Float1"),
									Crc.GetInstance().GenerateCrc("Float2"),
									Crc.GetInstance().GenerateCrc("Float3"),
									Crc.GetInstance().GenerateCrc("Float4")
								};

								List<Data.BufferDeclarationElement> elements = new List<Data.BufferDeclarationElement>();
								foreach (Document.Input bufinput in Util.getAllInputs(doc, primitive))
								{
									if (((Document.Source)bufinput.source).accessor.parameters[0].type != "float")
										throw new Exception("Found a vertex data source with non-float data. We don't support this yet!");

									Data.BufferDeclarationElement element = new Data.BufferDeclarationElement();
									element.name = Crc.GetInstance().GenerateCrc(bufinput.semantic);
									element.numElements = (UInt32)((Document.Source)bufinput.source).accessor.ParameterCount;
									element.type = floatTypes[element.numElements-1];
									element.semantic = Crc.GetInstance().GenerateCrc(bufinput.semantic);
									element.offset = (UInt32)curOffset;
									elements.Add(element);
									curOffset += (UInt32)(((Document.Source)bufinput.source).accessor.ParameterCount * 4);
								}

								decl.stride = curOffset;
								decl.idxFirstElement = renderData.AddObjects(elements);
								decl.numElements = (UInt32)elements.Count;
							}
							else
								if (((Document.Source)input.source).array != null)
									throw new Exception("Model was *not* transformed in vertexArray by Reindexor or equivalent conditionner");
						}
				}

				Data.Submodel submodel = ProcessSubmodel(primitive);
				submodel.idxVertexBuffer = idxVertexBuffer;
				submodels.Add(submodel);
			}

			lod.idxFirstSubmodel = renderData.AddObjects(submodels);
			lod.numSubmodels = (UInt32)submodels.Count;
		}

		private Data.Submodel ProcessSubmodel(Document.Primitive primitive)
		{
			Data.Submodel submodel = new Data.Submodel();

			if (!(primitive is Document.Triangle))
				throw new Exception("Unexpected primitiveType=" + primitive.GetType().ToString());

			submodel.numIndices = (UInt32)primitive.count * 3;
			submodel.firstVertex = UInt32.MaxValue;
			submodel.numVertices = UInt32.MinValue;
			submodel.firstIndex = 0;

			// Find material binding
			MaterialBinding matBinding = materialBindings[primitive.material];
			submodel.idxMaterial = renderData.GetObjectIndex(matBinding.boundMaterial);
			Debug.Assert(submodel.idxMaterial != -1);

			Data.Buffer indexBuffer = new Data.Buffer();
			submodel.idxIndexBuffer = renderData.AddObject(indexBuffer);
			indexBuffer.numElements = submodel.numIndices;
			indexBuffer.format = Data.BufferFormat.Index16Stream;
			for (int i = 0; i < primitive.p.Length; ++i)
			{
				submodel.firstVertex = Math.Min(submodel.firstVertex, (UInt32)primitive.p[i]);
				submodel.numVertices = Math.Max(submodel.numVertices, (UInt32)primitive.p[i]);
				if (primitive.p[i] > 65536)
				{
					indexBuffer.format = Data.BufferFormat.Index32Stream;
				}
			}
			submodel.numVertices = submodel.numVertices - submodel.firstVertex;

			switch (indexBuffer.format)
			{
				case Data.BufferFormat.Index16Stream:
					{
						UInt16[] indices = new UInt16[primitive.p.Length];
						for (int i = 0; i < primitive.p.Length; ++i)
						{
							indices[i] = (UInt16)primitive.p[i];
						}
						Byte[] initData = ByteConversion.ToByteArray(indices);
						indexBuffer.idxInitData = renderData.AddBoxedObjects(initData);
						indexBuffer.numInitDataBytes = (UInt32)initData.Length;
						break;
					}
				case Data.BufferFormat.Index32Stream:
					{
						UInt32[] indices = new UInt32[primitive.p.Length];
						for (int i = 0; i < primitive.p.Length; ++i)
						{
							indices[i] = (UInt32)primitive.p[i];
						}
						Byte[] initData = ByteConversion.ToByteArray(indices);
						indexBuffer.idxInitData = renderData.AddBoxedObjects(initData);
						indexBuffer.numInitDataBytes = (UInt32)initData.Length;
						break;
					}
				default:
					{
						break;
					}
			}

			return submodel;
		}
			
		private void ProcessNode(Document.Node node)
		{
			//System.Console.WriteLine(node.name);

			if (node.instances != null)
			{
				foreach (Document.Instance instance in node.instances)
				{
					if (instance is Document.InstanceGeometry)
					{
						Document.Geometry geo = (Document.Geometry)doc.dic[instance.url.Fragment];
						Data.Model tgtModel = modelLookup[geo];
						Int32 idxModel = renderData.GetObjectIndex(tgtModel);

						Data.Transform newTransform = new Data.Transform();
						if (node.transforms != null)
						{
							Matrix transform = new Matrix();
							transform.SetIdentity();
							foreach (Document.TransformNode transformNode in node.transforms)
							{
								if (transformNode is Document.Translate)
								{
									Matrix translation = new Matrix();
									translation.SetIdentity();
									translation.Translation.Set(transformNode[0], transformNode[1], transformNode[2], 1.0f);
									transform.PostMultiply(translation);
								}
								else if (transformNode is Document.Rotate)
								{
									Matrix rotX = new Matrix();
									Matrix rotY = new Matrix();
									Matrix rotZ = new Matrix();
									rotX.SetRotX(transformNode[0]);
									rotY.SetRotY(transformNode[1]);
									rotZ.SetRotZ(transformNode[2]);
									transform.PostMultiply(rotX.PreMultiply(rotY.PreMultiply(rotZ)));
								}
								else if (transformNode is Document.Scale)
								{
								}
								else if (transformNode is Document.Matrix)
								{
									Document.Matrix matrix = transformNode as Document.Matrix;
									for (int i = 0; i < 16; ++i)
									{
										newTransform.m[i] = matrix[i];
									}
								}
							}
						}

						Data.Instance newInstance = new Data.Instance();
						newInstance.idxModel = idxModel;
						newInstance.idxTransform = renderData.AddObject(newTransform);
						newInstance.flags = 0;
						newInstance.name = Crc.GetInstance().GenerateCrc(node.id);
						renderData.AddObject(newInstance);

						
					}
				}
			}


			if (node.children != null)
			{
				foreach (Document.Node child in node.children)
				{
					ProcessNode(child);
				}
			}
		}

		private void ProcessMaterial(Document.Material material)
		{
			Data.Material newMaterial = new Data.Material();
			renderData.AddObject(newMaterial);

			newMaterial.name = Crc.GetInstance().GenerateCrc(material.id);

			Document.Effect effect = (Document.Effect)doc.dic[material.instanceEffect.Fragment];

			Document.ProfileCOMMON profile = null;
			foreach (Document.IProfile tmpProfile in effect.profiles)
			{
				if (tmpProfile is Document.ProfileCOMMON)
				{
					profile = (Document.ProfileCOMMON)tmpProfile;
					break;
				}
			}

			if (profile == null)
				throw new Exception("No common profile found in material " + material.name);

			Document.SimpleShader shader = ((Document.ProfileCOMMON)profile).technique.shader;

			Data.RenderMethod newRenderMethod = new Data.RenderMethod();
		
			List<Data.Parameter> materialParams = new List<Data.Parameter>();

			List<String> requiredShaderBits = new List<String>();

			if (shader.diffuse is Document.Texture)
			{
				Document.Texture tex = (Document.Texture)shader.diffuse;
				String textureChannel = RemapTextureChannel(tex.texcoord);
				requiredShaderBits.Add("#define DEF_DIFFUSE_TEXTURE");
				requiredShaderBits.Add("#define DEF_ENABLE_" + textureChannel);
				requiredShaderBits.Add("#define DIFFUSE_TEXTURE_TEXCOORD " + textureChannel);

				string sampler = ((Document.Texture)shader.diffuse).texture;
				string surface = ((Document.Sampler2D)profile.newParams[sampler].param).source;
				string image = ((Document.Surface)profile.newParams[surface].param).initFrom;
				// now find image
				string imagePath = ((Document.Image)doc.dic[image]).init_from.Uri.LocalPath;
				Int32 idxTexture = CreateTexture(imagePath);

				Data.Parameter param = new Data.Parameter();
				param.name = Crc.GetInstance().GenerateCrc("g_DiffuseTexture");
				param.type = Crc.GetInstance().GenerateCrc("Texture");
				param.idxInitData = idxTexture;
				materialParams.Add(param);
			} 
			else if (shader.diffuse is Document.Color)
			{
				Document.Color color = (Document.Color)shader.diffuse;
				Data.Parameter param = new Data.Parameter();
				param.name = Crc.GetInstance().GenerateCrc("g_DiffuseColour");
				param.type = Crc.GetInstance().GenerateCrc("Float4");
				float[] floats = { color.floats[0], color.floats[1], color.floats[2], color.floats[3] };
				param.idxInitData = renderData.AddBoxedObjects(ByteConversion.ToByteArray(floats));
				materialParams.Add(param);
				requiredShaderBits.Add("#define DEF_DIFFUSE_FIXED");
			}

			if (shader.ambient is Document.Texture)
			{
				Document.Texture tex = (Document.Texture)shader.ambient;
				String textureChannel = RemapTextureChannel(tex.texcoord);
				requiredShaderBits.Add("#define DEF_AMBIENT_TEXTURE");
				requiredShaderBits.Add("#define DEF_ENABLE_" + textureChannel);
				requiredShaderBits.Add("#define AMBIENT_TEXTURE_TEXCOORD " + textureChannel);

				string sampler = ((Document.Texture)shader.ambient).texture;
				string surface = ((Document.Sampler2D)profile.newParams[sampler].param).source;
				string image = ((Document.Surface)profile.newParams[surface].param).initFrom;
				// now find image
				string imagePath = ((Document.Image)doc.dic[image]).init_from.Uri.LocalPath;
				Int32 idxTexture = CreateTexture(imagePath);

				Data.Parameter param = new Data.Parameter();
				param.name = Crc.GetInstance().GenerateCrc("g_AmbientTexture");
				param.type = Crc.GetInstance().GenerateCrc("Texture");
				param.idxInitData = idxTexture;
				materialParams.Add(param);
			}
			else if (shader.ambient is Document.Color)
			{
				Document.Color color = (Document.Color)shader.ambient;
				Data.Parameter param = new Data.Parameter();
				param.name = Crc.GetInstance().GenerateCrc("g_AmbientColour");
				param.type = Crc.GetInstance().GenerateCrc("Float4");
				float[] floats = { color.floats[0], color.floats[1], color.floats[2], color.floats[3] };
				param.idxInitData = renderData.AddBoxedObjects(ByteConversion.ToByteArray(floats));
				materialParams.Add(param);
				requiredShaderBits.Add("#define DEF_AMBIENT_FIXED");
			}

			if (shader.emission is Document.Texture)
			{
				Document.Texture tex = (Document.Texture)shader.emission;
				requiredShaderBits.Add("#define DEF_EMISSION_TEXTURE");
				requiredShaderBits.Add("#define DEF_ENABLE_" + tex.texcoord);
				requiredShaderBits.Add("#define EMISSION_TEXTURE_TEXCOORD " + tex.texcoord);

				string sampler = ((Document.Texture)shader.emission).texture;
				string surface = ((Document.Sampler2D)profile.newParams[sampler].param).source;
				string image = ((Document.Surface)profile.newParams[surface].param).initFrom;
				// now find image
				string imagePath = ((Document.Image)doc.dic[image]).init_from.Uri.LocalPath;
				Int32 idxTexture = CreateTexture(imagePath);

				Data.Parameter param = new Data.Parameter();
				param.name = Crc.GetInstance().GenerateCrc("g_EmissionTexture");
				param.type = Crc.GetInstance().GenerateCrc("Texture");
				param.idxInitData = idxTexture;
				materialParams.Add(param);
			}
			else if (shader.emission is Document.Color)
			{
				Document.Color color = (Document.Color)shader.emission;
				Data.Parameter param = new Data.Parameter();
				param.name = Crc.GetInstance().GenerateCrc("g_EmissiveColour");
				param.type = Crc.GetInstance().GenerateCrc("Float4");
				float[] floats = { color.floats[0], color.floats[1], color.floats[2], color.floats[3] };
				param.idxInitData = renderData.AddBoxedObjects(ByteConversion.ToByteArray(floats));
				materialParams.Add(param);
			}

			if (shader.specular is Document.Texture)
			{
				Document.Texture tex = (Document.Texture)shader.specular;
				requiredShaderBits.Add("#define DEF_SPECULAR_TEXTURE");
				requiredShaderBits.Add("#define DEF_ENABLE_" + tex.texcoord);
				requiredShaderBits.Add("#define SPECULAR_TEXTURE_TEXCOORD " + tex.texcoord);

				string sampler = ((Document.Texture)shader.specular).texture;
				string surface = ((Document.Sampler2D)profile.newParams[sampler].param).source;
				string image = ((Document.Surface)profile.newParams[surface].param).initFrom;
				// now find image
				string imagePath = ((Document.Image)doc.dic[image]).init_from.Uri.LocalPath;
				Int32 idxTexture = CreateTexture(imagePath);

				Data.Parameter param = new Data.Parameter();
				param.name = Crc.GetInstance().GenerateCrc("g_SpecularTexture");
				param.type = Crc.GetInstance().GenerateCrc("Texture");
				param.idxInitData = idxTexture;
				materialParams.Add(param);
			}
			else if (shader.specular is Document.Color)
			{
				Document.Color color = (Document.Color)shader.specular;
				Data.Parameter param = new Data.Parameter();
				param.name = Crc.GetInstance().GenerateCrc("g_SpecularColour");
				param.type = Crc.GetInstance().GenerateCrc("Float4");
				float[] floats = { color.floats[0], color.floats[1], color.floats[2], color.floats[3] };
				param.idxInitData = renderData.AddBoxedObjects(ByteConversion.ToByteArray(floats));
				materialParams.Add(param);
			}

			if (shader.transparency is Document.Texture)
			{
				Document.Texture tex = (Document.Texture)shader.transparency;
				requiredShaderBits.Add("#define DEF_TRANSPARENCY_TEXTURE");
				requiredShaderBits.Add("#define DEF_ENABLE_" + tex.texcoord);
				requiredShaderBits.Add("#define TRANSPARENCY_TEXTURE_TEXCOORD " + tex.texcoord);

				string sampler = ((Document.Texture)shader.transparency).texture;
				string surface = ((Document.Sampler2D)profile.newParams[sampler].param).source;
				string image = ((Document.Surface)profile.newParams[surface].param).initFrom;
				// now find image
				string imagePath = ((Document.Image)doc.dic[image]).init_from.Uri.LocalPath;
				Int32 idxTexture = CreateTexture(imagePath);

				Data.Parameter param = new Data.Parameter();
				param.name = Crc.GetInstance().GenerateCrc("g_TransparencyTexture");
				param.type = Crc.GetInstance().GenerateCrc("Texture");
				param.idxInitData = idxTexture;
				materialParams.Add(param);
			}
			else if (shader.transparency is Document.Float)
			{
				Document.Float color = (Document.Float)shader.transparency;
				Data.Parameter param = new Data.Parameter();
				param.name = Crc.GetInstance().GenerateCrc("g_Transparency");
				param.type = Crc.GetInstance().GenerateCrc("Float");
				float[] floats = { color.theFloat };
				param.idxInitData = renderData.AddBoxedObjects(ByteConversion.ToByteArray(floats));
				materialParams.Add(param);
			}

			newRenderMethod.idxGpuProgram = CreatePhongGpuProgram(requiredShaderBits);

			newMaterial.idxFirstRenderMethod = renderData.AddObject(newRenderMethod);
			newMaterial.numRenderMethods = 1;

			newMaterial.idxFirstParameter = renderData.AddObjects(materialParams);
			newMaterial.numParameters = (UInt32)materialParams.Count;
		}

		public Int32 CreatePhongGpuProgram(List<String> shaderBits)
		{
			Int32 idxGpuProgram = -1;
			String stdout = "";

			String shaderName = "";
			foreach (String s in shaderBits)
			{
				shaderName += s;
			}
			UInt32 shaderCRC = Crc.GetInstance().GenerateCrc(shaderName);

			if (gpuProgramCache.ContainsKey(shaderCRC))
			{
				idxGpuProgram = gpuProgramCache[shaderCRC];
			}
			else
			{
				shaderBits.Add("#include \"Z:\\Media\\BuildSource\\Shaders\\Collada\\Phong.hlsl\"");

				String inputFilename = Path.GetTempFileName();
				File.WriteAllLines(inputFilename, shaderBits.ToArray());

				String outputFilename = Path.GetTempFileName();
				Process p = new Process();
				p.StartInfo.FileName = @"Z:\ToolChain\Bin\GpuProgramCompiler.exe";
				p.StartInfo.Arguments = String.Format("/OUT:\"{0}\" /IN:\"{1}\" /PLATFORM:{2}", outputFilename, inputFilename, platform);
				p.StartInfo.CreateNoWindow = true;
				p.StartInfo.UseShellExecute = false;
				p.StartInfo.RedirectStandardOutput = true;
				p.Start();
				p.WaitForExit();
				stdout = p.StandardOutput.ReadToEnd();

				if (p.ExitCode == 0)
				{
					Byte[] shader = File.ReadAllBytes(outputFilename);
					Data.GpuProgram newGpuProgram = new Data.GpuProgram();
					newGpuProgram.name = shaderCRC;
					newGpuProgram.numInitDataBytes = (UInt32)shader.Length;
					newGpuProgram.idxInitDataBytes = renderData.AddBoxedObjects(shader);
					idxGpuProgram = renderData.AddObject(newGpuProgram);
					gpuProgramCache[shaderCRC] = idxGpuProgram;
				}

				File.Delete(inputFilename);
				File.Delete(outputFilename);
			}

			if (idxGpuProgram == -1)
				throw new Exception("Failed to compile shader:\n" + stdout);

			return idxGpuProgram;
		}

		public Int32 CreateTexture(String filename)
		{
			Int32 idxTexture = -1;
			UInt32 hsTextureFilename = Crc.GetInstance().GenerateCrc(filename);
			if (textureCache.ContainsKey(hsTextureFilename))
			{
				idxTexture = textureCache[hsTextureFilename];
			}
			else
			{
				//System.Console.WriteLine("Packaging Texture: " + filename);
				if (!File.Exists(filename))
					throw new FileNotFoundException("Couldn't find referenced source texture: " + filename);

				String tmpDir = Path.GetTempPath();

				Process p = new Process();
				p.StartInfo.FileName = @"Z:\ToolChain\Bin\texconv.exe";
				p.StartInfo.Arguments = "-f DXT5 -ft DDS -o " + tmpDir + " " + filename;
				p.StartInfo.UseShellExecute = false;
				p.StartInfo.CreateNoWindow = true;
				p.Start();
				p.WaitForExit();
				if (p.ExitCode != 0)
					throw new Exception("Failed to convert " + filename);

				String tmpFilename = tmpDir + Path.GetFileNameWithoutExtension(filename) + ".dds";

				if (!File.Exists(tmpFilename))
					throw new FileNotFoundException("Couldn't find converted texture: " + tmpFilename);

				Byte[] texBytes = File.ReadAllBytes(tmpFilename);
				File.Delete(tmpFilename);

				Data.Texture newTex = new Data.Texture();
				newTex.numInitDataBytes = (UInt32)texBytes.Length;
				newTex.idxInitData = renderData.AddBoxedObjects(texBytes);
				idxTexture = renderData.AddObject(newTex);

				textureCache[hsTextureFilename] = idxTexture;
			}
			return idxTexture;
		}

		private String RemapTextureChannel(String channel)
		{
			if (channel.Contains("0"))
				return "TEX0";
			else if (channel.Contains("1"))
				return "TEX0";
			else if (channel.Contains("2"))
				return "TEX1";
			else if (channel.Contains("3"))
				return "TEX2";
			return "TEX0";
		}
	}
}
